package com.gitee.lougnib.simplekits.common_impls.velocity2;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.context.Context;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
import org.apache.velocity.tools.ToolManager;

import com.gitee.lougnib.simplekits.common_faces.exception.Exceptions;

public class Velocity2Kit {

	/**
	 * 创建模板引擎的上下文。
	 *
	 * @param context 自定义的上下文
	 * @return 模板引擎的上下文
	 */
	public static Context createContext(Map<String, Object> context) {
		/**
		 * 默认情况下，下面的文件中的配置的Tool会自动配置：<br/>
		 * <br/>
		 * classpath:/org/apache/velocity/tools/generic/tools.xml<br/>
		 * classpath:/org/apache/velocity/tools/view/tools.xml<br/>
		 * classpath:/org/apache/velocity/tools/struts/tools.xml<br/>
		 * classpath:tools.xml<br/>
		 * classpath:tools.properties<br/>
		 * file:tools.xml<br/>
		 * file:tools.properties<br/>
		 */
		ToolManager manager = new ToolManager();
		manager.configure("tools.xml");
		Context vc = manager.createContext();
		Iterator<String> keyIt = context.keySet().iterator();
		while (keyIt.hasNext()) {
			String key = keyIt.next();
			vc.put(key, context.get(key));
		}
		return vc;
	}

	/**
	 * 文件路径的模板引擎缓存。
	 */
	private static Map<String, VelocityEngine> fileVelocityEngineCache = new HashMap<>();

	/**
	 * 取得文件路径的模板引擎。
	 *
	 * @param templateFolder 模板目录
	 * @return 模板引擎
	 */
	public static VelocityEngine getFileVelocityEngine(String templateFolder) {
		return getFileVelocityEngine(templateFolder, 1800);
	}

	/**
	 * 取得文件路径的模板引擎。
	 *
	 * @param templateFolder            模板目录
	 * @param modificationCheckInterval 缓存检查间隔，单位是秒
	 * @return 模板引擎
	 */
	public static VelocityEngine getFileVelocityEngine(String templateFolder, int modificationCheckInterval) {
		if (StringUtils.isEmpty(templateFolder)) {
			return null;
		}

		File templateFolderFile = new File(templateFolder);
		if (!templateFolderFile.exists()) {
			return null;
		}
		if (templateFolderFile.isFile()) {
			templateFolderFile = templateFolderFile.getParentFile();
		}

		String templateFolderPath = templateFolderFile.getAbsolutePath();
		if (fileVelocityEngineCache.containsKey(templateFolderPath)) {
			return fileVelocityEngineCache.get(templateFolderPath);
		}

		synchronized (fileVelocityEngineCache) {
			if (!fileVelocityEngineCache.containsKey(templateFolderPath)) {
				VelocityEngine ve = new VelocityEngine();
				setBasicProperties(ve);
				ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "file");
				ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, templateFolderPath);
				ve.setProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, "true");
				ve.setProperty("file.resource.loader.class", FileResourceLoader.class.getName());
				// 单位是秒。当值为负数时，将禁止检查功能。
				ve.setProperty("file.resource.loader.modificationCheckInterval",
						String.valueOf(modificationCheckInterval));
				ve.init();

				fileVelocityEngineCache.put(templateFolderPath, ve);
			}
		}

		return fileVelocityEngineCache.get(templateFolderPath);
	}

	/**
	 * 类路径的模板引擎。
	 */
	private static VelocityEngine classpathVelocityEngine = null;

	/**
	 * 取得类路径的模板引擎。
	 *
	 * @return 模板引擎
	 */
	public static VelocityEngine getClasspathVelocityEngine() {
		if (classpathVelocityEngine == null) {
			synchronized (Velocity2Kit.class) {
				if (classpathVelocityEngine == null) {
					VelocityEngine ve = new VelocityEngine();
					setBasicProperties(ve);
					ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
					ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
					ve.init();

					classpathVelocityEngine = ve;
				}
			}
		}

		return classpathVelocityEngine;
	}

	/**
	 * 字符串模板引擎。
	 */
	private static VelocityEngine stringVelocityEngine = null;

	/**
	 * 取得字符串模板引擎。
	 *
	 * @return 字符串模板引擎
	 */
	public static VelocityEngine getStringVelocityEngine() {
		if (stringVelocityEngine == null) {
			synchronized (Velocity2Kit.class) {
				if (stringVelocityEngine == null) {
					VelocityEngine ve = new VelocityEngine();
					setBasicProperties(ve);
					ve.init();

					stringVelocityEngine = ve;
				}
			}
		}

		return stringVelocityEngine;
	}

	/**
	 * 整合字符串模板。
	 *
	 * @param template 模板
	 * @param context  上下文
	 * @return 整合的结果
	 */
	public static String mergeStringTemplate(String template, Map<String, Object> context) {
		try (Writer writer = new StringWriter()) {

			getStringVelocityEngine().evaluate(Velocity2Kit.createContext(context), writer, "", template);
			writer.flush();

			return writer.toString();
		} catch (IOException e) {
			throw Exceptions.toRuntime(e, "合并模板失败。");
		}
	}

	/**
	 * 设置基本的属性。
	 *
	 * @param ve 模板引擎
	 */
	private static void setBasicProperties(VelocityEngine ve) {
		ve.setProperty(RuntimeConstants.INPUT_ENCODING, RuntimeConstants.ENCODING_DEFAULT);
		ve.setProperty("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.NullLogChute");
	}

}
